package main

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/canvas"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/storage"
	"fyne.io/fyne/v2/theme"
	"fyne.io/fyne/v2/widget"
	xWidget "fyne.io/x/fyne/widget"
	"github.com/Hermitter/fileman"
	"github.com/h2non/filetype"
)

// 设置选定目录
func (ui *fyles) setDirectory(u fyne.URI) {
	ui.pwd = u
	ui.itemTapped(nil)

	var items []fyne.CanvasObject
	parent, err := storage.Parent(u)
	if err == nil {
		up := &fileItem{parent: ui, name: "(Parent)", location: parent, dir: true}
		up.ExtendBaseWidget(up)
		up.view = ui.view
		items = append(items, up)
	}
	list, err := storage.List(u)
	if err != nil {
		fyne.LogError("Could not read dir", err)
	} else {
		for _, item := range list {
			if !ui.filter.Matches(item) {
				continue
			}
			dir, _ := storage.CanList(item)
			fi := newFileItem(item, dir, ui)
			fi.view = ui.view
			items = append(items, fi)
			// items = append(items, newFileItem(item, dir, ui))
		}
	}

	ui.items.Objects = items
	ui.items.Refresh()
	ui.fileScroll.ScrollToTop()
	// ui.filePath.SetText(u.Path())
	ui.win.SetTitle(winTitle + " : " + u.Name())
	buri.Set(u)
}

// 右键单击事件，弹出右键菜单
func (ui *fyles) itemTapped2(item *fileItem, e *fyne.PointEvent) {
	currentUI = ui
	buri.Set(ui.pwd)
	if ui.current != nil {
		ui.current.isCurrent = false
		ui.current.Refresh()
	}

	if item == nil {
		return
	}
	m := fyne.NewMenu("file",
		fyne.NewMenuItem("open", func() {
			if item.dir {
				ui.setDirectory(item.location)
				return
			} else {
				ui.viewer = fyne.CurrentApp().NewWindow("File viewer")
				ui.viewer.Resize(fyne.NewSize(400, 400))
				switch item.location.Extension() {
				case ".go", ".txt", ".mod", ".sum", ".bat", ".sh":
					bs, _ := os.ReadFile(item.location.Path())
					entry := widget.NewMultiLineEntry()
					entry.SetText(string(bs))
					ui.viewer.SetContent(entry)
					ui.viewer.Show()
				case ".jpg", ".png", ".jpeg":
					ui.viewer.SetContent(canvas.NewImageFromURI(item.location))
					ui.viewer.Show()
					/* 					entry := widget.NewEntry()
					   					f, r, err := pdf.Open(item.location.Path())
					   					// remember close file
					   					defer f.Close()
					   					if err != nil {
					   						msg.Set("read pdf error")
					   					}
					   					var buf bytes.Buffer
					   					b, err := r.GetPlainText()
					   					if err != nil {
					   						msg.Set("read pdf error")
					   					}
					   					buf.ReadFrom(b)
					   					entry.SetText(buf.String())
					   					ui.viewer.SetContent(entry) */
				default:
					OpenWithDefaultApp(item.location.Path())
					/* f, err := fileman.CopyFile(item.location.Path())
					if err != nil {
						ui.viewer.SetContent(widget.NewLabel("Nothing to show"))
						return
					}
					str, err := f.ToString()
					if err != nil {
						ui.viewer.SetContent(widget.NewLabel("Nothing to show"))
						return
					}
					entry := widget.NewMultiLineEntry()
					entry.SetText(str)
					ui.viewer.SetContent(entry)
					ui.viewer.Show() */
				}
			}
		}),
		fyne.NewMenuItem("Rename", func() {
			item.isRenaming = true
			item.Refresh()
		}),
		fyne.NewMenuItem("Delete", func() {
			fileman.Delete(item.location.Path())
			// storage.Delete(item.location)
			ui.items.Remove(item)
			msg.Set("Delete :" + item.location.Path())
		}),
		fyne.NewMenuItem("Copy path", func() {
			ui.win.Clipboard().SetContent(item.location.Path())
			msg.Set("Copy path :" + item.location.Path())
		}),
		fyne.NewMenuItem("Copy file to", func() {
			if item.dir {
				msg.Set("please choose a file to copy")
				return
			}
			copiedFile, err := fileman.CopyFile(item.location.Path())
			if err != nil {
				msg.Set("copy file err")
				return
			}

			dialog.ShowFolderOpen(func(lu fyne.ListableURI, e error) {
				if e != nil {
					return
				}
				if lu == nil {
					return
				}
				if ok, _ := storage.Exists(lu); ok {
					if err := copiedFile.Paste(lu.Path(), false); err != nil {
						msg.Set("paste error")
					}
					msg.Set("Copy " + item.location.Path() + " to " + lu.Path())
				}
			}, ui.win)
		}),
		fyne.NewMenuItem("Copy dir to ...", func() {
			if !item.dir {
				msg.Set("please choose a dir to copy")
				return
			}
			copiedDir, err := fileman.CopyDir(item.location.Path())
			if err != nil {
				msg.Set("copy file err")
				return
			}

			dialog.ShowFolderOpen(func(lu fyne.ListableURI, e error) {
				if e != nil {
					return
				}
				if lu == nil {
					return
				}
				if ok, _ := storage.Exists(lu); ok {
					if err := copiedDir.Paste(lu.Path(), false); err != nil {
						msg.Set("paste error")
					}
					msg.Set("Copy " + item.location.Path() + " to " + lu.Path())
				}
			}, ui.win)
		}),
		fyne.NewMenuItem("Zip", func() {
			destZip := ui.pwd.Path() + string(filepath.Separator) + item.name + ".zip"
			err := Zip(item.location.Path(), destZip)
			if err != nil {
				msg.Set("zip error:" + err.Error())
				return
			}
			ui.items.Add(newFileItem(storage.NewFileURI(destZip), false, ui))
			msg.Set("zip success")
		}),
		fyne.NewMenuItem("UnZip", func() {
			if item.location.Extension() != ".zip" {
				msg.Set("not a zip file")
				return
			}
			err := Unzip(item.location.Path(), ui.pwd.Path()+"/"+item.name)
			if err != nil {
				msg.Set("Unzip error:" + err.Error())
				return
			}
			ui.setDirectory(ui.pwd)
			msg.Set("Unzip success")
		}),
		fyne.NewMenuItem("Add to favorite", func() {
			if item.dir {
				bl.Append(item.location.Path())
			}
		}),
	)
	widget.ShowPopUpMenuAtPosition(m,
		fyne.CurrentApp().Driver().CanvasForObject(item), e.AbsolutePosition)
	ui.setStatus(item)

	ui.current = item
	item.isCurrent = true
	item.Refresh()
}

// 左键单击事件，如果是目录，则进入点击的目录；如果是文件，则在状态栏显示文件信息
func (ui *fyles) itemTapped(item *fileItem) {
	currentUI = ui
	buri.Set(ui.pwd)
	if ui.current != nil {
		ui.current.isCurrent = false
		ui.current.Refresh()
	}

	if item == nil {
		return
	}
	if item.dir {
		ui.setDirectory(item.location)
		return
	}
	ui.setStatus(item)

	ui.current = item
	item.isCurrent = true
	item.Refresh()
}

// 设置状态栏信息
func (ui *fyles) setStatus(item *fileItem) {
	fi, err := os.Lstat(item.location.Path())
	if err != nil {
		return
	}
	ft := ""
	// Open a file descriptor
	file, _ := os.Open(item.location.Path())
	defer file.Close()
	// We only have to pass the file header = first 261 bytes
	head := make([]byte, 261)
	file.Read(head)

	if filetype.IsImage(head) {
		ft = "Image"
	} else if filetype.IsAudio(head) {
		ft = "Audio"
	} else if filetype.IsDocument(head) {
		ft = "Document"
	} else if filetype.IsFont(head) {
		ft = "Font"
	} else if filetype.IsImage(head) {
		ft = "Image"
	} else if filetype.IsVideo(head) {
		ft = "Video"
	} else {
		ft = "Unkown"
	}
	msg.Set(fmt.Sprintf("%v: %v;FileType:%s, mod time:%s",
		fi.Name(), formatFileSize(fi.Size()), ft,
		fi.ModTime().Format("2006-01-02 15:04:05")))
}

// 构造左侧文件夹树
func (ui *fyles) makeFilesPanel(u fyne.URI) *xWidget.FileTree {
	vol := filepath.VolumeName(u.Path())
	if vol == "" {
		vol = "/"
	}

	root := storage.NewFileURI(vol)
	files := xWidget.NewFileTree(root)
	files.Filter = filterDir(ui.filter)
	files.Sorter = func(u1, u2 fyne.URI) bool {
		return u1.String() < u2.String() // Sort alphabetically
	}

	files.OnSelected = func(uid widget.TreeNodeID) {
		u, _ := storage.ParseURI(uid)
		currentUI.setDirectory(u)
		// ui.setDirectory(u)
	}

	files.Select(u.String())
	return files
}

func (f *fyles) setView(view viewLayout) {
	f.view = view
	if f.view == gridView {
		padding := fyne.NewSize(fileIconCellWidth-fileIconSize, theme.Padding())
		f.items = container.NewGridWrap(
			fyne.NewSize(fileIconSize, fileIconSize+fileTextSize).Add(padding),
		)
	} else {
		f.items = container.NewGridWithColumns(3)
		// f.items = container.NewVBox()
	}

	f.fileScroll.Content = container.NewPadded(f.items)
	// f.fileScroll.Refresh()
	f.setDirectory(f.pwd)
}

// 构造工具栏
func (ui *fyles) makeToolbar() *fyne.Container {
	// l := widget.NewLabel("")
	// ui.filePath = l
	ui.filePath = container.NewHBox()
	var toggleViewButton *widget.Button
	toggleViewButton = widget.NewButtonWithIcon("", theme.ListIcon(), func() {
		if currentUI.view == gridView {
			currentUI.setView(listView)
			toggleViewButton.SetIcon(theme.GridIcon())
		} else {
			currentUI.setView(gridView)
			toggleViewButton.SetIcon(theme.ListIcon())
		}
	})

	return container.NewBorder(nil, nil, widget.NewToolbar(
		widget.NewToolbarAction(theme.MoveUpIcon(), func() {
			p, err := storage.Parent(ui.pwd)
			if err != nil {
				return
			}
			ui.setDirectory(p)
		}),
		widget.NewToolbarAction(theme.FolderNewIcon(), func() {
			dialog.ShowEntryDialog("New Folder", "Name", func(s string) {
				if s == "" {
					return
				}
				os.Mkdir(s, 0777)
				ui.items.Add(newFileItem(storage.NewFileURI(s), true, ui))
				msg.Set("Create folder :" + s)
			}, ui.win)
		}),
		widget.NewToolbarAction(theme.HomeIcon(), func() {
			home, err := os.UserHomeDir()
			if err != nil {
				return
			}
			ui.setDirectory(storage.NewFileURI(home))
		}),
	), toggleViewButton,
		container.NewHScroll(ui.filePath))
	// container.NewHScroll(l))
}

// 使用按钮显示当前文件夹路径
func (f *fyles) setLocation(dir fyne.URI) error {
	if dir == nil {
		return fmt.Errorf("failed to open nil directory")
	}
	_, err := storage.ListerForURI(dir)
	if err != nil {
		return err
	}

	ui.filePath.Objects = nil

	localdir := dir.String()[len(dir.Scheme())+3:]

	buildDir := filepath.VolumeName(localdir)
	for i, d := range strings.Split(localdir, "/") {
		if d == "" {
			if i > 0 { // what we get if we split "/"
				break
			}
			buildDir = "/"
			d = "/"
		} else if i > 0 {
			buildDir = filepath.Join(buildDir, d)
		} else {
			d = buildDir
			buildDir = d + string(os.PathSeparator)
		}

		newDir := storage.NewFileURI(buildDir)
		isDir, err := storage.CanList(newDir)
		if err != nil {
			return err
		}

		if !isDir {
			return errors.New("location was not a listable URI")
		}
		ui.filePath.Add(
			widget.NewButton(d, func() {
				f.setDirectory(newDir)
			}),
		)
	}
	return nil
}
